package com.superme.common.exceptions;

import com.alibaba.fastjson2.JSON;
import com.superme.common.beans.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import javax.servlet.http.HttpServletRequest;

/**
 * 描述: 对全局异常的封装
 * 作者: yanruizhi
 * 时间: 2023/6/29 15:20
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler implements ResponseBodyAdvice<Object> {

    // 参数异常处理
    @ExceptionHandler(value = ParameterException.class)
    @ResponseBody
    public Result<Object> handleParameterException(ParameterException e, HttpServletRequest request) {
        logError(request, e);
        return Result.error(e.getCode(), e.getMsg());
    }

    // 业务异常处理
    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public Result<Object> handleBusinessException(BusinessException e, HttpServletRequest request) {
        logError(request, e);
        return Result.error(e.getCode(), e.getMsg());
    }

    // 登录异常处理
    @ExceptionHandler(value = LoginException.class)
    @ResponseBody
    public Result<Object> handleLoginException(LoginException e, HttpServletRequest request) {
        logError(request, e);
        return Result.error(e.getCode(), e.getMsg());
    }

    // 文件异常处理
    @ExceptionHandler(value = FileException.class)
    @ResponseBody
    public Result<Object> handleFileException(FileException e, HttpServletRequest request) {
        logError(request, e);
        return Result.error(e.getCode(), e.getMsg());
    }

    // 未知异常处理
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result<Object> handleUnknownException(Exception e, HttpServletRequest request) {
        logError(request, e);
        return Result.error(e.getMessage());
    }

    // JSON参数异常的处理
    @Override
    protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        Result<Object> error = Result.error("请求参数JSON为空或JSON格式异常");
        return ResponseEntity.status(status).headers(headers).body(error);
    }

    private void logError(HttpServletRequest request, Exception e) {
        if (e instanceof BusinessException) {
            log.error("url: {}, message: {}", request.getRequestURL(), ((BusinessException) e).getMsg(), e);
        } else if (e instanceof ParameterException) {
            log.error("url: {}, message: {}", request.getRequestURL(), ((ParameterException) e).getMsg(), e);
        } else if (e instanceof LoginException) {
            log.error("url: {}, message: {}", request.getRequestURL(), ((LoginException) e).getMsg(), e);
        } else if (e instanceof FileException) {
            log.error("url: {}, message: {}", request.getRequestURL(), ((FileException) e).getMsg(), e);
        } else {
            log.error("url: {}, message: {}", request.getRequestURL(), e.getMessage(), e);
        }
    }


    /**
     * 判断是否需要对响应体进行处理（即是否执行beforeBodyWrite方法）
     */
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        // 如果body已经是Result类型，则直接返回，否则包装成Result类型
        if (body instanceof Result) {
            return body;
        } else {
            //处理String类型的返回值由于 StringHttpMessageConverter转换器导致的类型转换异常问题
            Result<Object> success = Result.OK(body);
            return body instanceof String ? JSON.toJSONString(success) : success;
        }
    }
}
